//------------------------------------------------------------------------------
// The contents of this file are subject to the nopCommerce Public License Version 1.0 ("License"); you may not use this file except in compliance with the License.
// You may obtain a copy of the License at  http://www.nopCommerce.com/License.aspx. 
// 
// Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. 
// See the License for the specific language governing rights and limitations under the License.
// 
// The Original Code is nopCommerce.
// The Initial Developer of the Original Code is NopSolutions.
// All Rights Reserved.
// 
// Contributor(s): _______. 
//------------------------------------------------------------------------------

using System;
using System.Collections.Generic;
using System.Text;
using Tathata.Common.Caching;
using Microsoft.Practices.EnterpriseLibrary.Data;
using System.Data.Common;
using System.Data;
using System.Globalization;
using Tathata.Common.DAL;
using System.Security.Cryptography;
using Tathata.Common.Utils;
using System.Web.Security;
using Tathata.Common.BLL.Entities;
using Tathata.Common.Localization;
using Tathata.Common.BLL.EntityCollections;
using Tathata.Common.DAL.Managers;
using System.Web;
using Tathata.Common.BLL.Enums;

namespace Tathata.Common.BLL.Managers
{
    /// <summary>
    /// Customer manager
    /// </summary>
    public class CustomerManager
    {
        #region Methods
       

        /// <summary>
        /// Sets a customer email
        /// </summary>
        /// <param name="CustomerID">Customer identifier</param>
        /// <param name="NewEmail">New email</param>
        public static void SetEmail(int CustomerID, string NewEmail)
        {
            if (!CommonHelper.IsValidEmail(NewEmail))
                throw new Exception("New email is not valid");
            Customer customer = GetByCustomerID(CustomerID);
            if (customer != null)
            {
                UpdateCustomer(customer.CustomerID, customer.CustomerGUID, NewEmail,
                    customer.PasswordHash, customer.SaltKey, customer.AffiliateID, 
                    customer.LanguageID, customer.CurrencyID, customer.IsAdmin, customer.Active,
                    customer.Deleted, customer.RegistrationDate);
            }
        }

        /// <summary>
        /// Gets all customers
        /// </summary>
        /// <returns>Customer collection</returns>
        public static CustomerCollection GetAllCustomers()
        {
            return CustomerDBManager.GetAllCustomers();
        }

        /// <summary>
        /// Gets all customers by affiliate identifier
        /// </summary>
        /// <param name="AffiliateID">Affiliate identifier</param>
        /// <returns>Customer collection</returns>
        public static CustomerCollection GetByAffiliateID(int AffiliateID)
        {
            return CustomerDBManager.GetByAffiliateID(AffiliateID);
        }

        /// <summary>
        /// Gets all customers by customer role id
        /// </summary>
        /// <param name="CustomerRoleID">Customer role identifier</param>
        /// <returns>Customer collection</returns>
        public static CustomerCollection GetByCustomerRoleID(int CustomerRoleID)
        {
            bool showHidden = NopContext.Current.IsAdmin;
            return CustomerDBManager.GetByCustomerRoleID(CustomerRoleID, showHidden);
        }

        /// <summary>
        /// Marks customer as deleted
        /// </summary>
        /// <param name="CustomerID">Customer identifier</param>
        public static void MarkCustomerAsDeleted(int CustomerID)
        {
            Customer customer = GetByCustomerID(CustomerID);
            if (customer != null)
            {
                UpdateCustomer(customer.CustomerID, customer.CustomerGUID, customer.Email, customer.PasswordHash,
                    customer.SaltKey, customer.AffiliateID,
                    customer.LanguageID, customer.CurrencyID, customer.IsAdmin, customer.Active, true, customer.RegistrationDate);
            }
        }

        /// <summary>
        /// Gets a customer by email
        /// </summary>
        /// <param name="Email">Customer Email</param>
        /// <returns>A customer</returns>
        public static Customer GetByEmail(string Email)
        {
            return CustomerDBManager.GetByEmail(Email);
        }

        /// <summary>
        /// Gets a customer
        /// </summary>
        /// <param name="CustomerID">Customer identifier</param>
        /// <returns>A customer</returns>
        public static Customer GetByCustomerID(int CustomerID)
        {
            return CustomerDBManager.GetByCustomerID(CustomerID);
        }

        /// <summary>
        /// Gets a customer by GUID
        /// </summary>
        /// <param name="CustomerGUID">Customer GUID</param>
        /// <returns>A customer</returns>
        public static Customer GetByCustomerGUID(Guid CustomerGUID)
        {
            return CustomerDBManager.GetByCustomerGUID(CustomerGUID);
        }

        /// <summary>
        /// Adds a customer
        /// </summary>
        /// <param name="Email">The email</param>
        /// <param name="Password">The password</param>
        /// <param name="AffiliateID">The affiliate identifier</param>
        /// <param name="IsAdmin">A value indicating whether the customer is administrator</param>
        /// <param name="Active">A value indicating whether the customer is active</param>
        /// <param name="status">Status</param>
        /// <returns>A customer</returns>
        public static Customer AddCustomer(string Email, string Password, int AffiliateID, bool IsAdmin,
            bool Active, out MembershipCreateStatus status)
        {
            return AddCustomer(Guid.NewGuid(), Email, Password, AffiliateID,0,0,IsAdmin, Active, false, DateTime.Now, out status);
        }

        /// <summary>
        /// Adds a customer
        /// </summary>
        /// <param name="CustomerGUID">The customer identifier</param>
        /// <param name="Email">The email</param>
        /// <param name="Password">The password</param>
        /// <param name="AffiliateID">The affiliate identifier</param>
        /// <param name="LanguageID">The language identifier</param>
        /// <param name="CurrencyID">The currency identifier</param>
        /// <param name="IsAdmin">A value indicating whether the customer is administrator</param>
        /// <param name="Active">A value indicating whether the customer is active</param>
        /// <param name="Deleted">A value indicating whether the customer has been deleted</param>
        /// <param name="RegistrationDate">The date and time of customer registration</param>
        /// <param name="status">Status</param>
        /// <returns>A customer</returns>
        protected static Customer AddCustomer(Guid CustomerGUID, string Email,
            string Password, int AffiliateID,
            int LanguageID, int CurrencyID,
            bool IsAdmin, bool Active, bool Deleted, DateTime RegistrationDate,
            out MembershipCreateStatus status)
        {
            Customer customer = null;
            status = MembershipCreateStatus.UserRejected;
            if ((GetByEmail(Email) != null))
            {
                status = MembershipCreateStatus.DuplicateEmail;
                return customer;
            }

            if (!CommonHelper.IsValidEmail(Email))
            {
                status = MembershipCreateStatus.InvalidEmail;
                return customer;
            }
            bool registrationEmailValidation = SettingManager.GetSettingValueBoolean("Customer.RegistrationEmailValidation");
            Active = Active ? !registrationEmailValidation : Active;

            string saltKey = CreateSalt(5);
            string passwordHash = CreatePasswordHash(Password, saltKey);

            customer = CustomerDBManager.AddCustomer(CustomerGUID, Email,
                passwordHash, saltKey, AffiliateID,
                LanguageID, CurrencyID,
                IsAdmin, Active, Deleted, RegistrationDate);

            CustomerSessionManager.SaveCustomerSession(Guid.NewGuid(), customer.CustomerID, DateTime.Now, false);

            status = MembershipCreateStatus.Success;

            if (Active)
                MessageManager.SendCustomerWelcomeMessage(customer);
            else
                MessageManager.SendCustomerEmailValidationMessage(customer);
            return customer;
        }

        /// <summary>
        /// Updates the customer
        /// </summary>
        /// <param name="CustomerID">The customer identifier</param>
        /// <param name="CustomerGUID">The customer identifier</param>
        /// <param name="Email">The email</param>
        /// <param name="PasswordHash">The password hash</param>
        /// <param name="SaltKey">The salk key</param>
        /// <param name="AffiliateID">The affiliate identifier</param>
        /// <param name="LanguageID">The language identifier</param>
        /// <param name="CurrencyID">The currency identifier</param>
        /// <param name="IsAdmin">A value indicating whether the customer is administrator</param>
        /// <param name="Active">A value indicating whether the customer is active</param>
        /// <param name="Deleted">A value indicating whether the customer has been deleted</param>
        /// <param name="RegistrationDate">The date and time of customer registration</param>
        /// <returns>A customer</returns>
        public static Customer UpdateCustomer(int CustomerID, Guid CustomerGUID, string Email,
            string PasswordHash, string SaltKey, int AffiliateID,
            int LanguageID,
            int CurrencyID, bool IsAdmin, bool Active, bool Deleted, DateTime RegistrationDate)
        {
            return CustomerDBManager.UpdateCustomer(CustomerID, CustomerGUID, Email,
             PasswordHash, SaltKey, AffiliateID,
             LanguageID,
             CurrencyID, IsAdmin, Active, Deleted, RegistrationDate);
        }

        /// <summary>
        /// Modifies password
        /// </summary>
        /// <param name="Email">Customer email</param>
        /// <param name="Oldpassword">Old password</param>
        /// <param name="Password">Password</param>
        public static void ModifyPassword(string Email, string Oldpassword, string Password)
        {
            Customer customer = GetByEmail(Email);
            if (customer != null)
            {
                string oldPasswordHash = CreatePasswordHash(Oldpassword, customer.SaltKey);
                if (!customer.PasswordHash.Equals(oldPasswordHash))
                    throw new Exception("Current Password doesn't match.");
                string newPasswordSalt = CreateSalt(5);
                string newPasswordHash = CreatePasswordHash(Password, newPasswordSalt);
                UpdateCustomer(customer.CustomerID, customer.CustomerGUID, customer.Email, newPasswordHash,
                    newPasswordSalt, customer.AffiliateID,
                    customer.LanguageID, customer.CurrencyID, customer.IsAdmin, customer.Active,
                    customer.Deleted, customer.RegistrationDate);
            }
        }

        /// <summary>
        /// Modifies password
        /// </summary>
        /// <param name="Email">Customer email</param>
        /// <param name="NewPassword">New password</param>
        public static void ModifyPassword(string Email, string NewPassword)
        {
            Customer customer = GetByEmail(Email);
            if (customer != null)
            {
                string newPasswordSalt = CreateSalt(5);
                string newPasswordHash = CreatePasswordHash(NewPassword, newPasswordSalt);
                UpdateCustomer(customer.CustomerID, customer.CustomerGUID, customer.Email, newPasswordHash,
                    newPasswordSalt, customer.AffiliateID,
                    customer.LanguageID, customer.CurrencyID, customer.IsAdmin, customer.Active,
                    customer.Deleted, customer.RegistrationDate);
            }
        }

        /// <summary>
        /// Activates a customer
        /// </summary>
        /// <param name="CustomerGUID">Customer identifier</param>
        public static void Activate(Guid CustomerGUID)
        {
            Customer customer = GetByCustomerGUID(CustomerGUID);
            if (customer != null)
            {
                UpdateCustomer(customer.CustomerID, customer.CustomerGUID, customer.Email,
                    customer.PasswordHash, customer.SaltKey, customer.AffiliateID,
                    customer.LanguageID, customer.CurrencyID, customer.IsAdmin, true,
                    customer.Deleted, customer.RegistrationDate);
            }
        }

        /// <summary>
        /// Deactivates a customer
        /// </summary>
        /// <param name="CustomerGUID">Customer identifier</param>
        public static void Deactivate(Guid CustomerGUID)
        {
            Customer customer = GetByCustomerGUID(CustomerGUID);
            if (customer != null)
            {
                UpdateCustomer(customer.CustomerID, customer.CustomerGUID, customer.Email,
                    customer.PasswordHash, customer.SaltKey, customer.AffiliateID,
                    customer.LanguageID, customer.CurrencyID,
                    customer.IsAdmin, false, customer.Deleted, customer.RegistrationDate);
            }
        }

        /// <summary>
        /// Login a customer
        /// </summary>
        /// <param name="Email">A customer email</param>
        /// <param name="Password">Password</param>
        /// <returns>Result</returns>
        public static bool Login(string Email, string Password)
        {
            Customer customer = GetByEmail(Email);
            if (customer == null)
                return false;
            if (!customer.Active)
                throw new Exception("Account is disabled");
            if (customer.Deleted)
                throw new Exception("Account is deleted");
            string str = CreatePasswordHash(Password, customer.SaltKey);
            bool result = customer.PasswordHash.Equals(str);
            if (result)
            {
                CustomerSession registeredCustomerSession = CustomerSessionManager.GetByCustomerID(customer.CustomerID);
                if (registeredCustomerSession != null)
                {
                    registeredCustomerSession.IsExpired = false;
                }
                if (NopContext.Current.Session == null)
                    NopContext.Current.Session = NopContext.Current.GetSession(true);
                NopContext.Current.Session.IsExpired = false;
                NopContext.Current.Session.LastAccessed = DateTime.Now;
                NopContext.Current.Session.CustomerID = customer.CustomerID;
                CustomerSessionManager.SaveCustomerSession(NopContext.Current.Session.CustomerSessionGUID, NopContext.Current.Session.CustomerID, NopContext.Current.Session.LastAccessed, NopContext.Current.Session.IsExpired);
            }
            return result;
        }

        /// <summary>
        /// Logout customer
        /// </summary>
        public static void Logout()
        {
            //bool flag = NopContext.CheckSessionParameters();
            //if (flag)
            //{
            //    CustomerSession session = NopContext.Current.Session;
            //    if (session != null)
            //    {
            //        session.IsExpired = true;
            //        CustomerSessionManager.SaveCustomerSession(session.CustomerSessionGUID, session.CustomerID, session.LastAccessed, session.IsExpired);
            //    }
            //}
            NopContext.Current.ResetSession();

            if (HttpContext.Current.Session != null)
                HttpContext.Current.Session.Abandon();
            FormsAuthentication.SignOut();
        }

        /// <summary>
        /// Creates a password hash
        /// </summary>
        /// <param name="Password">Password</param>
        /// <param name="Salt">Salt</param>
        /// <returns>Password hash</returns>
        private static string CreatePasswordHash(string Password, string Salt)
        {
            return FormsAuthentication.HashPasswordForStoringInConfigFile(Password + Salt, "SHA1");
        }

        /// <summary>
        /// Creates a salt
        /// </summary>
        /// <param name="size">A salt size</param>
        /// <returns>A salt</returns>
        private static string CreateSalt(int size)
        {
            RNGCryptoServiceProvider provider = new RNGCryptoServiceProvider();
            byte[] data = new byte[size];
            provider.GetBytes(data);
            return Convert.ToBase64String(data);
        }
        #endregion
    }
}
